<?php


/**
 * 载入淘宝 api 处理类
 */
require('taoapi/Taoapi.php');

/**
 * 载入缓存处理类
 */
require('sync/cache.php');


/**
 * 载入产品处理类
 */
require('sync/products.php');

/**
 * 载入同步异常处理类
 */
require('sync/exception.php');

/**
 * 定义行分隔符
 */
define('LINE_SEP', "\n------------------------------------------------------------------\n");

/**
 * 淘宝产品数据同步
 *
 * @copyright  www.360hqb.com
 * @author   Y.N
 *
 */
class CLI_Syncp extends CLI
{

	/**
	 * CLI主方法
	 *
	 * @param	none
	 * @access	public
	 * @return	void
	 * @update	2011/9/30
	*/
	public function main()
	{
		self::sync_product_data();

	} // end func


	/**
	 * 获取淘宝最顶层类目（写入缓存）
	 *
	 * @param	none
	 * @access	public
	 * @return	array
	 * @update	2011/3/24
	*/
	public static function get_taobao_top_cats()
	{
		// 获取缓存
		$Sync_Cache = new Sync_Cache();
		$top_cats = json_decode($Sync_Cache->get_cache('topcats'));
		if (empty($top_cats))
		{
		    $top_cats = self::get_taobao_cats(0);
			// 写入缓存
			$data = json_encode($top_cats);
			$Sync_Cache->save_cache('topcats',$data);
		}
		return $top_cats;
	} // end func

	/**
	 * 获取360hqb子叶类目
	 *
	 * @param	int $parent_cid
	 * @access	public
	 * @return	array
	 * @update	2011/3/22
	*/
	public static function get_root_cats($parent_cid = 0)
	{
		$root_cats = array();

		$item_cats = DB::select('cid')
			->from('item_cats')
			->where('parent_cid', '=',$parent_cid)
			->fetch_all();

		if ($item_cats)
		{
			foreach ($item_cats as $key => $value)
			{
				$root_cats = array_merge($root_cats,self::get_root_cats($value['cid']));
			}
		}else {
			$root_cats[] = $parent_cid;
		}
		return $root_cats;
	} // end func


	/**
	 * 通过API获取淘宝类目数据
	 *
	 * @param	int $cid
	 * @access	public
	 * @return	object
	 * @update	2011/3/22
	*/
	public static function get_taobao_cats($cid)
	{
		// 判断是否数字类型
		assert("is_numeric('$cid')");
		$url = "http://open.taobao.com/api_tool/props/ajaxProps.php?cid=$cid&action=childCid&restBool=false";

		// 获取数据
		$i = 1;
		while (true) {
			$data = @file_get_contents($url);
			if ($data !== false) {
                break;
			} else {
                CLI::output ('.');
                sleep($i++);
			}
		}

		// 反编码
        $std = json_decode($data);
		if ( ! empty($data))
		{
		    return isset($std->itemcats_get_response->item_cats->item_cat) ?
                $std->itemcats_get_response->item_cats->item_cat :
                new stdClass();
		}else {
		    return new stdClass();
		}
	} // end func




	/**
	 * 保存产品数据
	 *
	 * @param	none
	 * @access	public
	 * @return	void
	 * @update	2011/3/25
	*/
	public static function save_products()
	{
		// 自动退出时间
		$time = strtotime(date('Y-m-d 08:15:s'));

	    CLI::output(LINE_SEP."正在获取子叶类目数据...");
		$new_array = array();

		// 获取子叶类目缓存
		$date = date("Ymd");
		$Sync_Cache = new Sync_Cache();
		$data = $Sync_Cache->get_cache('rootcats_'.$date);
		$root_cats = json_decode($data);
		if (empty($root_cats))
		{
		    $root_cats = self::get_root_cats();
		}
		CLI::output(LINE_SEP."正在同步产品...");

		foreach ($root_cats as $k => $cat)
		{
			// 自动退出脚本
			if (time() >= $time)
			{
				exit('自动退出脚本');
			}

			// 检测是否锁定分类
			$lock = $Sync_Cache->get_cache('product_'.$cat);
			if (self::locked($cat) OR $lock)
			{
			    continue;
			}
			try{
                $total = (int) Sync_Products::remoteTotal($cat);
				// 获取产品总数
				$original = DB::select(DB::expr('count(*)'))
					->from('products')
					->where('cid', '=', $cat)
					->fetch_one();

				// 未确认产品计数
				$undown_count = 0;
				// 已经下载完成计数
                $down_count = 0;
				// 新增下载计数
				$new_count = 0;

				if ($total)
				{
					// 写入日志
					new Sync_Exception('子叶类目：('.$cat.')下共 '.$total.' 个产品，已下载 '.$original.' 个产品', 376, __FUNCTION__, __CLASS__);

				    for ($i = 1; $i <= ceil($total / 10); $i++)
					{
						// 获取产品列表
                        $products = (array) Sync_Products::remoteList($cat, $i, 10);
						$i == 1 && CLI::output("\n");

						foreach ($products as $p)
						{
							// 查询产品库是否已下载
                            $found = DB::select(DB::expr('count(*)'))
                                ->from('products')
                                ->where('product_id', '=', $p['product_id'])
                                ->fetch_one();
                            if ($found)
							{
                                $down_count++;
                                continue;
                            }

                            // 通过api远程下载
                            $data = Sync_Products::remoteData($p['product_id']);

							// 写入远程图片路径
                            if (isset($data['pic_url']))
							{
                                $data['pic_url'] = preg_replace('/http:\/\/img0[0-9]\.taobaocdn.com\/bao\/uploaded\//i', '', $data['pic_url']);
                            }
                            isset($data['price']) && $data['market_price'] = $data['price'];
                            isset($data['name']) && $data['product_name'] = $data['name'];
                            isset($data['tsc']) && $data['product_sn']   = $data['tsc'];
                            isset($data['desc']) && $data['product_desc'] = $data['desc'];

                            // 只下载已确认的产品
                            if ($data['status'] != 3)
							{
                                $undown_count++;
                                continue;
                            }
							// 保存产品图片
                            if (isset($data['product_imgs']['product_img']))
							{
                                $imgdata = $data['product_imgs']['product_img'];
                                if ( ! empty($imgdata))
								{
                                    if (is_array($imgdata))
									{
									    foreach ($imgdata as $img)
									    {
											 DB::replace('product_imgs', $img)->execute();
									    }
									}else {
										DB::replace('product_imgs', $imgdata)->execute();
									}
                                }
                                unset($imgdata);
                            }
							unset($data['price'], $data['name'], $data['tsc'], $data['desc'], $data['product_imgs'], $data['product_prop_imgs']);

							// 写入数据库
                            if (is_array($data))
							{
								// 判断是否存在手动录入的产品相同
								$product_id = DB::select('product_id')
									->from('products')
									->where('props', '=', $data['props'])
									->where('cid', '=', $data['cid'])
									->where('is_new', '=',1)
									->fetch_one();
								if ($product_id)
								{
									// 删除该产品
									DB::delete('products')->where('product_id', '=', $product_id)->execute();
								    // 取出关联商品
									$goods = DB::select('goods_id')
										->from('goods')
										->where('product_id', '=', $product_id)
										->fetch_all();
									if ($goods)
									{
										$new_array[] = $data['props'];
										$new_array[] = $data['binds'];

										$props = implode(';', $new_array);
										unset($new_array);

										$props_array = explode(';',$props);

										foreach ($goods as $g)
										{
											// 更新商品表
											$set = array(
												'product_id' => $data['product_id'],
												'props' => $props,
												'props_str' => $data['props_str'].';'.$data['binds_str'],
											);
											DB::update('goods')->set($set)->where('product_id', '=', $product_id)->execute();

											// 更新产品图片
											DB::update('product_imgs')
												->set(array('product_id'=>$data['product_id']))
												->where('product_id', '=', $product_id)
												->execute();

											// 删除商品属性表关联数据
											DB::delete('goods_props')->where('goods_id', '=', $g['goods_id'])->execute();

											// 商品属性属性值录入
											if ( ! empty($props_array))
											{
												foreach ($props_array as $p)
												{
													if ( ! empty($p) AND strstr($p, ':'))
													{
														DB::replace('goods_props', array('goods_id' => $g['goods_id'],'props' => $p))->execute();
													}
												}
											}
											unset($props_array);
										}
									}
								}
                                DB::replace('products', $data)->execute();
								// 写入日志
								$msg = '---------->新增产品('.$data['product_name'].'['.$data['product_id'].'])';
								new Sync_Exception($msg, '子叶类目ID：'.$cat, __FUNCTION__, __CLASS__);
								// 新增计数+1
                                $new_count++;
                            }
                            unset($data);
						}
						unset($products);
					}
					unset($i);
				}
				// 全部下载 写入日志
				$msg = '======>未确认产品：'.$undown_count.'个，已认证下载：('.$down_count.')个产品，新增：('.$new_count.')个产品';
				new Sync_Exception($msg, '子叶类目ID：'.$cat,  __FUNCTION__, __CLASS__);

				// 如果未确认下载产品数量较多，锁定分类
				if ($undown_count >=200)
				{
					self::lock($cat, 1);
				}
				// 缓存分类
				$Sync_Cache->save_cache('product_'.$cat, 1);

                unset($total, $undown_count, $down_count, $new_count, $msg);

			}catch (Exception $e) {
                CLI::output("\n\n错误：".$e->getMessage()." ×\n");
            }
		}
		unset($root_cats);
	} // end func


	/**
	 * 判断分类下载是否锁定
	 *
	 * @param  int  $cid
	 * @return bool
	 */
	public static function locked($cid)
	{
		return is_file(TMPPATH."/logs/lock/$cid.lock");
	}

	/**
	 * 锁定分类下载
	 *
	 * @param  int  $cid
	 * @param  int  $total
	 */
	public static function lock($cid, $total = 0)
	{
		$path = TMPPATH."/logs/lock/";
		$file = $path."$cid.lock";
		if ( ! dir($path))
		{
		    mkdir($path, 0777);
		}
		file_put_contents($file, $total);
	}


	/**
	 * 同步产品数据
	 *
	 * @param	none
	 * @access	public
	 * @return	void
	 * @update	2011/5/25
	*/
	public static function sync_product_data()
	{
	    /* 同步产品，写入日志 */
		new Sync_Exception('|-------|同步产品开始', ':',  __FUNCTION__, __CLASS__);

		self::save_products();

		new Sync_Exception('|-------|同步产品结束', ':',  __FUNCTION__, __CLASS__);

	} // end func

} // end class





